//
//  PPNetCenter.m
//  PPNetworking
//
//  Created by 邓标祥 on 2020/12/15.
//

#import "PPNetCenter.h"
#import "PPNetEngine.h"
#import "PPNetError.h"
#import "PPNetCustomRequest.h"
#import <PPLog/PPLog-Swift.h>

static NSString *const xBatchRequestMark = @"BC";

@interface PPNetCenter(){
    dispatch_semaphore_t _lock;
}
@property (nonatomic, strong) PPNetEngine *engine;
@property (nonatomic, assign) NSUInteger autoIncrement;
@property (nonatomic, copy, nullable) NSString *generalServer;
@property (nonatomic, strong, readwrite) NSMutableDictionary<NSString *, id> *generalParameters;
@property (nonatomic, strong, readwrite) NSMutableDictionary<NSString *, NSString *> *generalHeaders;
@property (nonatomic, strong) NSMutableDictionary<NSString *, id> *runningBatchAndChainPool;
@end

@implementation PPNetCenter

+ (instancetype)defaultCenter {
    static id sharedInstance = nil;
    static dispatch_once_t onceToken;
    dispatch_once(&onceToken, ^{
        sharedInstance = [[PPNetCenter alloc] init];
    });
    return sharedInstance;
}

- (instancetype)init {
    if (self = [super init]) {
        _autoIncrement = 0;
        _engine = [PPNetEngine sharedEngine];
        _lock = dispatch_semaphore_create(1);
    }
    return self;
}

+ (NSString *)sendRequest:(PPNetRequest *)request
                onSuccess:(PPNetSuccessBlock)successBlock
                onFailure:(PPNetFailureBlock)failureBlock{
    return [[self defaultCenter] sendRequest:request onSuccess:successBlock onFailure:failureBlock];
}

+ (NSString *)sendBatchRequest:(PPNetBatchRequestConfigBlock)configBlock onFinished:(PPBCFinishedBlock)finishedBlock{
    return [[self defaultCenter] sendBatchRequest:configBlock onFinished:finishedBlock];
}

+ (void)cancelRequest:(NSString *)identifier {
    [[self defaultCenter] cancelRequest:identifier];
}

+ (void)cancelAllRequest{
    [[self defaultCenter] cancelAllRequest];
}

+ (void)setupConfig:(void(^)(PPNetConfig *config))block {
    [[self defaultCenter] setupConfig:block];
}

- (void)setGeneralHeaderValue:(NSString *)value forField:(NSString *)field {
    [self.generalHeaders setValue:value forKey:field];
}

- (void)setGeneralParameterValue:(id)value forKey:(NSString *)key {
    [self.generalParameters setValue:value forKey:key];
}

#pragma mark -
///< 全局网络配置
- (void)setupConfig:(void(^)(PPNetConfig *config))block {
    PPNetConfig *config = [[PPNetConfig alloc] init];
    config.consoleLog = NO;
    !block?:block(config);
    
    if (config.generalServer) {
        self.generalServer = config.generalServer;
    }
    if (config.generalParameters.count > 0) {
        [self.generalParameters addEntriesFromDictionary:config.generalParameters];
    }
    if (config.generalHeaders.count > 0) {
        [self.generalHeaders addEntriesFromDictionary:config.generalHeaders];
    }
    self.consoleLog = config.consoleLog;
}

///< 发送单个请求
- (NSString *)sendRequest:(PPNetRequest *)request
                onSuccess:(PPNetSuccessBlock)successBlock
                onFailure:(PPNetFailureBlock)failureBlock{
    if (!request) {
        return nil;
    }
    /// 先配置请求信息
    [self pp_configRequest:request onSuccess:successBlock onFailure:failureBlock onFinished:nil];
    /// 发送请求
    [self pp_sendRequest:request];
    
    return request.identifier;
}

///< 发送批量请求
- (NSString *)sendBatchRequest:(PPNetBatchRequestConfigBlock)configBlock
              onFinished:(PPBCFinishedBlock)finishedBlock{
    PPNetBatchRequest *batchRequest = [[PPNetBatchRequest alloc]init];
    !configBlock?:configBlock(batchRequest);
    
    if (batchRequest.requestArray.count > 0) {
        if (finishedBlock) {
            [batchRequest setValue:finishedBlock forKey:@"_finishedBlock"];
        }
        /// 循环集合里的请求对象
        for (PPNetRequest *request in batchRequest.requestArray) {
            /// 配置请求信息
            [self pp_configRequest:request
                         onSuccess:nil
                         onFailure:nil
                        onFinished:^(id  _Nullable responseObject, NSError * _Nullable error) {
//                @PPWeakObj(self);
                __weak typeof(self)weakSelf = self;
                if ([batchRequest onFinishedOneRequest:request
                                              response:responseObject
                                                 error:error]) {
                    /// 批量请求结束后，从缓存池中移除
//                    @PPStrongObj(self);
                    __strong typeof(weakSelf) strongSelf = weakSelf;
                    dispatch_semaphore_wait(self->_lock, DISPATCH_TIME_FOREVER);
                    [self.runningBatchAndChainPool removeObjectForKey:batchRequest.identifier];
                    dispatch_semaphore_signal(self->_lock);
                }
            }];
            /// 发送请求
            [self pp_sendRequest:request];
        }
    }
    NSString *identifier = [self pp_identifierForBatchAndChainRequest];
    [batchRequest setValue:identifier forKey:@"_identifier"];
    /// 我锁
    dispatch_semaphore_wait(_lock, DISPATCH_TIME_FOREVER);
    /// 批量请求对象加到缓存池
    [self.runningBatchAndChainPool setValue:batchRequest forKey:identifier];
    /// 我解锁
    dispatch_semaphore_signal(_lock);
    
    return identifier;
}

///< 取消请求
- (void)cancelRequest:(NSString *)identifier{
    if (!identifier) return;
    id request = nil;
    if ([identifier hasPrefix:xBatchRequestMark]) {
        // 批量请求
        dispatch_semaphore_wait(_lock, DISPATCH_TIME_FOREVER);
        request = [self.runningBatchAndChainPool objectForKey:identifier];
        [self.runningBatchAndChainPool removeObjectForKey:identifier];
        dispatch_semaphore_signal(_lock);
        if ([request isKindOfClass:[PPNetBatchRequest class]]) {
            PPNetBatchRequest *batchRequest = request;
            if (batchRequest.requestArray.count > 0) {
                for (PPNetRequest *rq in batchRequest.requestArray) {
                    if (rq.identifier.length > 0) {
                        [self.engine cancelRequestByIdentifier:rq.identifier];
                    }
                }
            }
        }
    } else if (identifier.length > 0) {
        // 单请求
       [self.engine cancelRequestByIdentifier:identifier];
    }
}

///< 取消全部请求
- (void)cancelAllRequest{
    [self.engine cancelAllOperations];
}

#pragma mark -- 私有方法
/// 发送请求
- (void)pp_sendRequest:(PPNetRequest *)request{
    
    [self.engine sendRequest:request completionHandler:^(id  _Nullable responseObject, NSError * _Nullable error) {
        
        if (error) {
            /// 网络层请求失败
            [self pp_failureWithError:error responseObject:responseObject forRequest:request];
        }else{
            /// 网络层请求成功
            [self pp_successWithResponse:responseObject forRequest:request];
        }
    }];
}


#pragma mark - 网络层请求成功
/// 网络层请求成功
/// @param responseObject
/// @param error 业务层的error对象
/// @param request request
- (void)pp_successWithResponse:(id)responseObject
                    forRequest:(PPNetRequest *)request{
    
#if DEBUG
    if (self.consoleLog) {
        // ppwang.com/timestamp 不打印
        if (![request.url containsString:@"ppwang.com/timestamp"]) {
            if (request.requestType == PPNetRequest_normal) {
                if (request.responseSerializerType == PPNetResponseSerializer_raw) {
                    
                    NSLog(@"\n============ [请求URL] ===========\n%@ \n============ [请求参数] ===========\n%@ \n============ [响应数据] =========== \n", request.url, request.parameters);
                    NSLog(@"%@\n==========================================\n", [[NSString alloc] initWithData:responseObject encoding:NSUTF8StringEncoding]);
                } else {
                    NSLog(@"\n============ [请求URL] ===========\n%@ \n============ [请求参数] ===========\n%@ \n============ [响应数据] =========== \n", request.url, request.parameters);
                    NSLog(@"%@\n==========================================\n", responseObject);
                }
            }
        }
    }
#endif
    
    if (request.successBlock) {
        if (request.isAnalyticData) {
            /// 解析转换数据
            [request classModelWithResponseObject:responseObject onResultBlock:^(id  _Nullable resultObject, PPNetError * _Nullable resultError) {
                if (resultObject) {
                    //数据解析转换成功
                    !request.successBlock?:request.successBlock(resultObject);
                }else{
                    
                    if (resultError && resultError.code != PPNetError_emptyData) {
                        if (resultError.code == PPNetError_emptyData) {
                            
                            //空数据
                            NSString *message = [NSString stringWithFormat:@"(空数据)---\nurl=%@", request.url];
                            [PPLog infoWithTag:@"net" message:message];
                        } else {
                            //失败
                            NSString *message = [NSString stringWithFormat:@"(解析错误)---\nurl=%@\nheader=%@\nparam=%@\nresponseData=%@\nerrorCode=%ld\nerrorMessage=%@", request.url, request.headers, request.parameters, responseObject,(long)resultError.code, resultError.message];
                            [PPLog infoWithTag:@"net" message:message];
                        }
                    }
                    !request.failureBlock?:request.failureBlock(resultError);
                    if (resultError.code == PPNetError_no_login ||
                        resultError.code == PPNetError_loginCheckoutFailure ||
                        resultError.code == PPNetError_tokenInvalid) {
//                        Login *login = [Login loadLoginInfo];
//                        if (login) {
//                            [login clear];
//                        }
                        [[NSNotificationCenter defaultCenter] postNotificationName:@"k_Network_Request_logout" object:nil];
                    }
                    
                }
            }];
        }else{
            !request.successBlock?:request.successBlock(responseObject);
        }
    }
    
    !request.finishedBlock?:request.finishedBlock(responseObject, nil);
    [request cleanCallbackBlocks];
}

/// 网络层请求失败
/// @param error error
/// @param request request
- (void)pp_failureWithError:(id)errorModel
             responseObject:(id)responseObject
                 forRequest:(PPNetRequest *)request {
    
    NSError *error = nil;
    PPNetError *netError = nil;
    if ([errorModel isKindOfClass:PPNetError.class]) {
        netError = errorModel;
        error = netError.systemError;
    } else if ([errorModel isKindOfClass:NSError.class]) {
        error = errorModel;
    }
    
#if DEBUG
    if (self.consoleLog) {
        if (self.consoleLog) {
            NSLog(@"\n=========== [请求错误] ===========\nrequest url: %@ \nerror info: \n%@\n==========================================\n", request.url, error);
        }
    }
    
//    [self pp_sentryWithError:netError responseObject:responseObject forRequest:request];
    
#endif
    
    if (error) {
        
        [PPLog infoWithTag:@"net" message:[NSString stringWithFormat:@"(网络层请求失败)\nurl=%@\nheader=%@\nparam=%@\nresponseData=%@\nerrorInfo=%@", request.url, request.headers, request.parameters, responseObject,error.userInfo]];
    }
    
    PPNetError *ppError = [PPNetError errorWithSystemError:error];
    
    if (ppError.code == NSURLErrorCancelled) {
        // 如果失败类型是请求被取消，就不回调到外层
        return;
    }
    
    !request.failureBlock?:request.failureBlock(ppError);
    !request.finishedBlock?:request.finishedBlock(nil, error);
    [request cleanCallbackBlocks];
}

/// 上报错误到Sentry
- (void)pp_sentryWithError:(PPNetError *)netError
            responseObject:(id)responseObject
                forRequest:(PPNetRequest *)request {
#if DEBUG
    
    BOOL needSend = NO;
    if (netError) {
        if ([request isKindOfClass:PPJavaRequest.class]) {
            if (netError.code != PPNetError_emptyData) {
                needSend = YES;
            }
        } else if ([request isKindOfClass:PPPhpRequest.class]) {
            if (netError.code != 200) {
                needSend = YES;
            }
        }
    }
    
    if (needSend) {
        NSMutableString *string = [[NSMutableString alloc] init];
        [string appendString:@"\n=========== [请求错误] ===========\n"];
        if (netError) {
            [string appendString:@"----- 错误信息 -----\n"];
            [string appendFormat:@"msg = %@, code = %ld\n", netError.message, (long)netError.code];
        }
        NSString *method = @"";
        switch (request.httpMethod) {
            case PPNetHTTPMethod_GET:
                method = @"GET";
                break;
            case PPNetHTTPMethod_POST:
                method = @"POST";
                break;
            default:
                break;
        }
        [string appendFormat:@"----- URL %@ -----\n", method];
        [string appendFormat:@"%@\n", request.url];
        [string appendString:@"----- headers -----\n"];
        [string appendFormat:@"%@\n", request.headers];
        [string appendString:@"----- parameters -----\n"];
        [string appendFormat:@"%@\n", request.parameters];
        [string appendString:@"----- 返回数据 -----\n"];
        [string appendFormat:@"%@\n", responseObject];
//        [string appendString:@"----- errorInfo -----\n"];
//        [string appendFormat:@"%@\n", error.userInfo];
//        SentryMessage *message = [[SentryMessage alloc] initWithFormatted:string];
//        SentryEvent *event = [[SentryEvent alloc] initWithLevel:kSentryLevelError];
//        event.message = message;
//        [SentrySDK captureEvent:event];
    }
#endif
}

/// 配置请求对象
/// @param request request
/// @param successBlock 网络层成功block
/// @param failureBlock 网络成失败block
/// @param finishedBlock 请求结束的block
- (void)pp_configRequest:(PPNetRequest *)request
               onSuccess:(PPNetSuccessBlock)successBlock
               onFailure:(PPNetFailureBlock)failureBlock
              onFinished:(PPNetFinishedBlock)finishedBlock{
    ///< block通过kvc绑定
    if (successBlock) {
        [request setValue:successBlock forKey:@"_successBlock"];
    }
    if (failureBlock) {
        [request setValue:failureBlock forKey:@"_failureBlock"];
    }
    if (finishedBlock) {
        [request setValue:finishedBlock forKey:@"_finishedBlock"];
    }
    
    /// 设置通用服务器地址
    if (request.useGeneralServer && self.generalServer && self.generalServer.length > 0) {
        request.server = [self.generalServer copy];
    }
    
    /// 设置通用请求参数
    if (request.useGeneralParameters && self.generalParameters.count > 0) {
        NSMutableDictionary *parameters = [NSMutableDictionary dictionary];
        [parameters addEntriesFromDictionary:self.generalParameters];
        if (request.parameters.count > 0) {
            [parameters addEntriesFromDictionary:request.parameters];
        }
        request.parameters = parameters;
    }
    
    /// 设置通用header
    if (request.useGeneralHeaders && self.generalHeaders.count > 0) {
        NSMutableDictionary *headers = [NSMutableDictionary dictionary];
        [headers addEntriesFromDictionary:self.generalHeaders];
        if (request.headers) {
            [headers addEntriesFromDictionary:request.headers];
        }
        request.headers = headers;
    }
    
    /// 请求地址拼接
    if (request.url.length == 0) {
        if (request.server.length == 0 && request.useGeneralServer && self.generalServer.length > 0) {
            request.server = self.generalServer;
        }
        request.url = [NSString stringWithFormat:@"%@%@", request.server?:@"", request.api?:@""];
    }
}

#pragma mark - 设置批量请求唯一标识
- (NSString *)pp_identifierForBatchAndChainRequest {
    NSString *identifier = nil;
    dispatch_semaphore_wait(_lock, DISPATCH_TIME_FOREVER);
    self.autoIncrement++;
    identifier = [NSString stringWithFormat:@"%@%lu", xBatchRequestMark,(unsigned long)self.autoIncrement];
    dispatch_semaphore_signal(_lock);
    return identifier;
}

- (NSMutableDictionary<NSString *, id> *)generalParameters {
    if (!_generalParameters) {
        _generalParameters = [NSMutableDictionary dictionary];
    }
    return _generalParameters;
}

- (NSMutableDictionary<NSString *, NSString *> *)generalHeaders {
    if (!_generalHeaders) {
        _generalHeaders = [NSMutableDictionary dictionary];
    }
    return _generalHeaders;
}

- (NSMutableDictionary<NSString *, id> *)runningBatchAndChainPool {
    if (!_runningBatchAndChainPool) {
        _runningBatchAndChainPool = [NSMutableDictionary dictionary];
    }
    return _runningBatchAndChainPool;
}

@end


/// ************************************ 全省港澳所有既分割线唯独呢条至靓仔 ************************************ ///

@implementation PPNetConfig
@end
